package com.ksd.web.controller.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ksd.common.config.PlayControlConfig;
import com.ksd.common.core.domain.AjaxResult;
import com.ksd.common.utils.StringUtils;
import com.ksd.quartz.util.TaskConstans;
import com.ksd.system.domain.SysBoard;
import com.ksd.system.domain.SysChannel;
import com.ksd.system.domain.SysChannelTemplate;
import com.ksd.system.domain.SysFreq;
import com.ksd.system.service.*;
import com.ksd.web.controller.m3beans.*;
import com.ksd.web.controller.process.ProcessStatusEnum;
import com.ksd.web.controller.system.SysChannelSearchController;
import com.ksd.web.controller.tool.ContOsTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static com.ksd.common.core.domain.AjaxResult.error;
import static com.ksd.common.core.domain.AjaxResult.success;

@Service
public class AsyncService {

    public final Logger logger = LoggerFactory.getLogger(AsyncService.class);
    @Autowired
    private SendChannelService sendChannelService;
    @Autowired
    private ISysBoardService sysBoardService;
    @Autowired
    private ISysChannelTemplateService sysChannelTemplateService;
    @Autowired
    private ISysOperLogService sysOperLogService;
    @Autowired
    private SearchChannelService searchChannelService;
    @Autowired
    private OutputChannelService outputChannelService;
    @Autowired
    private ISysChannelService sysChannelService;
    @Autowired
    private ISysFreqService sysFreqService;
    @Autowired
    private ProcessService processService;

    /**
     * 异步执行重启网络
     */
    @Async("asyncNetworkConfig") // 复用之前的线程池
    public void asyncNetworkConfig() {
        logger.info("异步修改主板网络服务");
        try {
            // 延迟1秒执行，确保接口有足够时间返回响应
            Thread.sleep(1000);
            // 执行网络重启
            ContOsTool.rebootService();

            // 可选：记录重启日志
            logger.info("网络服务已异步重启");
        } catch (InterruptedException e) {
            logger.error("网络重启线程被中断", e);
            Thread.currentThread().interrupt();
        } catch (Exception e) {
            logger.error("网络重启失败", e);
        }
    }

    /**
     * 异步执行一键配置业务逻辑（核心：步骤埋点）
     */
    @Async("asyncClearAgainScanExecutor") // 复用之前的线程池
    public void executeConfigProcess(String processId) {
        try {
            // 1. 更新任务状态为“处理中”
            processService.updateProcessStatus(processId, ProcessStatusEnum.PROCESSING);
            processService.addStep(processId, "任务启动", "开始处理所有直播板卡（板卡1、板卡2）");

            // 2. 原业务逻辑：获取板卡列表（步骤埋点）
            SysBoard sysBoard1 = sysBoardService.selectSysBoardById(Long.valueOf(TaskConstans.boardValue1));
            SysBoard sysBoard2 = sysBoardService.selectSysBoardById(Long.valueOf(TaskConstans.boardValue2));
            List<SysBoard> sysBoards = new ArrayList<>();
            if (sysBoard1 != null) sysBoards.add(sysBoard1);
            if (sysBoard2 != null) sysBoards.add(sysBoard2);
            processService.addStep(processId, "获取板卡列表", "共获取到" + sysBoards.size() + "个板卡（板卡ID：" +
                    sysBoards.stream().map(b -> b.getId().toString()).collect(Collectors.joining(",")) + "）");

            // 3. 遍历板卡执行核心逻辑（每个步骤都加埋点）
            Boolean clearChannleFlag1 = false;
            Boolean clearChannleFlag2 = false;
            for (SysBoard sysBoard : sysBoards) {
                String boardId = sysBoard.getId().toString();
                String boardName = sysBoard.getName();

                // 3.1 清除频道数据（步骤1）
                processService.addStep(processId, "清除频道数据", "开始清除板卡【" + boardName + "（ID：" + boardId + "）】的频道数据");
                int resetResult = searchChannelService.resetProgramDbsData(sysBoard);
                if (resetResult == 0) {
                    processService.addStep(processId, "清除频道数据", "板卡【" + boardName + "】清除成功");
                } else {
                    processService.addStep(processId, "清除频道数据", "板卡【" + boardName + "】清除失败（返回码：" + resetResult + "）");
                    continue; // 清除失败，跳过后续步骤
                }

                // 3.2 开始频道扫描（步骤2）
                processService.addStep(processId, "开始频道扫描", "板卡【" + boardName + "】开始频道扫描（频率：12020，符号率：28800）");
                StartChannelScanData scanData = new StartChannelScanData();
                scanData.setBoard(boardId);
                scanData.setPolarization(3);
                scanData.setSymbolRate(28800);
                scanData.setFrequency(12020);
                int startResult = searchChannelService.startChannelScan(sysBoard, scanData);
                if (startResult != 0) {
                    processService.addStep(processId, "开始频道扫描", "板卡【" + boardName + "】扫描启动失败（返回码：" + startResult + "）");
                    continue;
                }

                // 3.3 循环查询扫描结果（步骤3）
                processService.addStep(processId, "循环查询扫描", "板卡【" + boardName + "】进入循环查询扫描状态");
                int searchResult = 1;
                int retryCount = 0;
                do {
                    searchResult = searchChannelService.repeatedSearchM3GetService(sysBoard);
                    retryCount++;
                    // 避免日志过多，每5次查询记录一次步骤
                    if (retryCount % 5 == 0) {
                        processService.addStep(processId, "循环查询扫描", "板卡【" + boardName + "】第" + retryCount + "次查询，当前状态：扫描中（返回码：1）");
                    }
                } while (searchResult == 1);
                processService.addStep(processId, "循环查询扫描", "板卡【" + boardName + "】扫描结束（最终返回码：" + searchResult + "）");

                // 3.4 停止扫描并更新状态（步骤4）
                if (searchResult == 0) {
                    processService.addStep(processId, "停止频道扫描", "板卡【" + boardName + "】开始停止扫描并获取最新频道");
                    int stopResult = searchChannelService.stopChannelScan(sysBoard);
                    if (stopResult == 0) {
                        processService.addStep(processId, "停止频道扫描", "板卡【" + boardName + "】停止扫描成功");
                        if (TaskConstans.boardValue1.equals(boardId)) clearChannleFlag1 = true;
                        if (TaskConstans.boardValue2.equals(boardId)) clearChannleFlag2 = true;
                    } else {
                        processService.addStep(processId, "停止频道扫描", "板卡【" + boardName + "】停止扫描失败（返回码：" + stopResult + "）");
                    }
                }
            }

            // 4. 清空未成功洗牌的板卡数据（步骤5）
            processService.addStep(processId, "处理未成功洗牌板卡", "开始清理未成功重新扫描的板卡频道配置");
            // 板卡1处理（原逻辑，添加步骤埋点）
            if (!clearChannleFlag1) {
                processService.addStep(processId, "处理未成功洗牌板卡", "板卡1（ID：" + TaskConstans.boardValue1 + "）未成功扫描，开始清空原有配置");
                // 原清空逻辑...
                processService.addStep(processId, "处理未成功洗牌板卡", "板卡1原有配置清空完成");
            }
            // 板卡2处理（同理）
            if (!clearChannleFlag2) {
                processService.addStep(processId, "处理未成功洗牌板卡", "板卡2（ID：" + TaskConstans.boardValue2 + "）未成功扫描，开始清空原有配置");
                // 原清空逻辑...
                processService.addStep(processId, "处理未成功洗牌板卡", "板卡2原有配置清空完成");
            }

            // 5. 重新分发默认频道（步骤6）
            processService.addStep(processId, "重新分发默认频道", "开始为成功扫描的板卡分发默认频道");
            // 原分发逻辑...（每个板卡分发成功/失败都加步骤埋点）
            if (clearChannleFlag1) {
                AjaxResult ajaxResult1 = setSysChannleUpdate(sysBoard1); // 原分发方法
                if (ajaxResult1.isSuccess()) {
                    processService.addStep(processId, "重新分发默认频道", "板卡1默认频道分发成功");
                } else {
                    processService.addStep(processId, "重新分发默认频道", "板卡1默认频道分发失败（原因：" + ajaxResult1.get(AjaxResult.MSG_TAG) + "）");
                }
            }
            if (clearChannleFlag2) {
                AjaxResult ajaxResult2 = setSysChannleUpdate(sysBoard2);
                if (ajaxResult2.isSuccess()) {
                    processService.addStep(processId, "重新分发默认频道", "板卡2默认频道分发成功");
                } else {
                    processService.addStep(processId, "重新分发默认频道", "板卡2默认频道分发失败（原因：" + ajaxResult2.get(AjaxResult.MSG_TAG) + "）");
                }
            }

            // 6. 任务完成（步骤7）
            processService.addStep(processId, "任务结束", "一键配置所有步骤执行完成");
            processService.updateProcessStatus(processId, ProcessStatusEnum.COMPLETED);

        } catch (Exception e) {
            // 异常处理：记录错误步骤，更新任务状态为失败
            processService.addStep(processId, "任务异常", "处理过程中发生错误：" + e.getMessage());
            processService.updateProcessStatus(processId, ProcessStatusEnum.FAILED);
            logger.error("一键配置任务异常（processId：" + processId + "）", e);
        }
    }

    @Async("asyncExecutor")
    public CompletableFuture<String> sendChannelListManageDataAsync(Long boardId) {
        AjaxResult channelListManage = sendChannelService.getChannelListManage(boardId);
        logger.info("异步查询直播板卡"+boardId+"的结果: "+channelListManage.toString());

        logger.info("===================sendChannelListManageDataAsync异步处理接口完成===================");
        return CompletableFuture.completedFuture("Data sent successfully");
    }



    @Async("asyncZipDataExecutor")
    public CompletableFuture<String> sendAsyncZipDataExecutor(Long boardId) {
        AjaxResult channelListManage = sendChannelService.getChannelListManage(boardId);
        logger.info("异步处理从云服务器下处理的待同步的电影和电视剧"+boardId+"的结果: "+channelListManage.toString());

        logger.info("===================sendChannelListManageDataAsync异步处理接口完成===================");
        return CompletableFuture.completedFuture("Data sent successfully");
    }

    public AjaxResult setSysChannleUpdate(SysBoard sysBoard) {
//        System.out.println("开始进行默认分发频道设置:"+sysBoard.getUrl());
        //在停止查询接口会进行频道搜索,会将所有频道重新插入数据库中,等待1秒
        //查询频道表是否有数据,如果有数据,开始进行频道默认分发处理
        List<SysChannel> sysChannels = new ArrayList<>();
        if (TaskConstans.boardValue1.equals(sysBoard.getId().toString())) {
//            System.out.println("直播板卡1");
            sysChannels = sysChannelService.selectSysChannelList(new SysChannel(), SysChannel.table_one);
//            System.out.println("个数:"+sysChannels.size());
        }else if(TaskConstans.boardValue2.equals(sysBoard.getId().toString())) {
//            System.out.println("直播板卡2");
            sysChannels = sysChannelService.selectSysChannelList(new SysChannel(), SysChannel.table_twice);
//            System.out.println("size:"+sysChannels.size());
        }
        logger.info("查询到的最新频道列表数据个数:"+sysChannels.size()+"============直播板卡id:"+sysBoard.getId());
        if (sysChannels.size() != 0) {
            logger.info("开始进行直播板卡:" + sysBoard.getId() + " 的节目分发");
            SysChannelTemplate sysChannelTemplate = new SysChannelTemplate();
            sysChannelTemplate.setPush(sysBoard.getId());
            List<SysChannelTemplate> sysChannelTemplates = sysChannelTemplateService.selectSysChannelTemplateList(sysChannelTemplate);
            logger.info("该直播板卡设置的默认配置的频道个数:" + sysChannelTemplates.size());
            //进行默认分发
            DeliveryParamObject deliveryParamObject = new DeliveryParamObject();
            deliveryParamObject.setBordId(sysBoard.getId().toString());
            Set<String> freqs = new HashSet<>();
            List<SysChannel> selectedChannels = new ArrayList<>();


            List<SaveServiceInfo> saveServiceInfoList = new ArrayList<>();
            for (SysChannelTemplate channelTemplate : sysChannelTemplates) {
                String name = channelTemplate.getName();
                SysChannel sysChannel = new SysChannel();
                if (TaskConstans.boardValue1.equals(sysBoard.getId().toString())) {
                    sysChannel = sysChannelService.selectSysChannelByName(name, SysChannel.table_one);
                } else if (TaskConstans.boardValue2.equals(sysBoard.getId().toString())) {
                    sysChannel = sysChannelService.selectSysChannelByName(name, SysChannel.table_twice);
                }
                if (sysChannel != null) {
                    selectedChannels.add(sysChannel);//默认选中的分发频道
                    logger.info("选中默认配置的频道有:" + sysChannel.getName() + "=====频道表:" + sysChannel.getId() + "==============" + sysChannel.getFreq());
                    //默认分发频道有限制,当前默认分发频道个数为不允许超过6个
                    freqs.add(sysChannel.getFreq().toString());
                }
            }

            //重新针对各个高频头选择默认分发
            List<SysChannel> selectedChannelsCountList = new ArrayList<>();
            for (String everyFreq : freqs) {
                //有2个高频头,平均每个分配2个频道
                int count = 0;
                for (SysChannel selectedChannel : selectedChannels) {
                    Long freq = selectedChannel.getFreq();
//                    if (everyFreq.equals(freq.toString()) && count < Long.valueOf(PlayControlConfig.getSelectSysChannelSingleCount())) {
                    if (everyFreq.equals(freq.toString())) {
                        selectedChannelsCountList.add(selectedChannel);
                        count ++;
                    }
                }
            }
            logger.info("设置默认分发频道个数:" + selectedChannels.size() + ",频率freqs size:" + freqs.size());
            selectedChannels = new ArrayList<>();
            for (SysChannel sysChannel : selectedChannelsCountList) {
                selectedChannels.add(sysChannel);
            }
            logger.info("重新根据当前直播板卡每次最多允许配置频道个数,设置默认分发频道个数:" + selectedChannels.size() + ",频率freqs size:" + freqs.size());
            List<DeliveryParam> deliveryParam = new ArrayList<>();
            for (String freq : freqs) {
                DeliveryParam delivery = new DeliveryParam();
                delivery.setSymbolRate(28800);
                delivery.setPolarization(3);
                delivery.setFrequency(Integer.valueOf(freq));
                deliveryParam.add(delivery);
            }
            deliveryParamObject.setDeliveryParam(deliveryParam);

            int mainFreqExResult = outputChannelService.setMainFreqEx(sysBoard, deliveryParamObject);
            logger.info("开始进行设置默认分发频道,setMainFreqEx接口结果:" + mainFreqExResult);
            if (mainFreqExResult == 0) {

                for (String freq : freqs) {
                    List<SaveService> serviceInfoObjectList = new ArrayList<>();
                    Long onid = 0L;
                    Long tsid = 0L;
                    Long symbolRate = 0L;
                    SaveServiceInfo saveServiceInfo = new SaveServiceInfo();
                    for (int i = 0; i < selectedChannels.size(); i++) {
                        SysChannel selectedChannel = selectedChannels.get(i);
                        Long freqResult = selectedChannel.getFreq();
                        if (freq.equals(freqResult.toString())) {
//                            System.out.println("freqResult:" + freqResult);
//                            logger.info("freqResult:" + freqResult+",默认选中:" + selectedChannel.getName());
                            onid = selectedChannel.getOnid();
                            tsid = selectedChannel.getTsid();
//                            System.out.println(onid + "===================tsId:" + tsid);
//                                                symbolRate = selectedChannel.getSymbolRate();
                            SaveService serviceInfoObject = new SaveService();
                            serviceInfoObject.setId(Integer.valueOf(selectedChannel.getPmtpid().toString()));
                            serviceInfoObject.setName(selectedChannel.getName());
                            serviceInfoObject.setProtocol("udp");
                            serviceInfoObject.setIp(selectedChannel.getIp());
                            serviceInfoObject.setPort(Integer.valueOf(selectedChannel.getPort()));
                            serviceInfoObject.setUrl("");
                            serviceInfoObjectList.add(serviceInfoObject);
                        }
                    }
                    System.out.println("saveServiceList:" + serviceInfoObjectList.size());
                    saveServiceInfo.setServiceinfo(serviceInfoObjectList);
                    saveServiceInfo.setOnid(Integer.valueOf(onid.toString()));
                    saveServiceInfo.setTsid(Integer.valueOf(tsid.toString()));
//                                        saveServiceInfo.setFrequency(Integer.valueOf(freq.toString()));
//                                        saveServiceInfo.setSymbolRate(Integer.valueOf(symbolRate.toString()));
                    saveServiceInfoList.add(saveServiceInfo);
                }
                //开始进行保存
                SaveSatelliteInfo saveSatelliteInfo = new SaveSatelliteInfo();
                saveSatelliteInfo.setBoard(sysBoard.getId().toString());
                saveSatelliteInfo.setSatellite("1");//1表示高频头1  2表示高频头2
                saveSatelliteInfo.setServiceInfo(saveServiceInfoList);
//                System.out.println("开始设置重新分发默认频道");
                AjaxResult ajaxResult = outputChannelService.setPrfDataSave(sysBoard, saveSatelliteInfo);
//                System.out.println("======保存频道结果========:" + ajaxResult.toString());
                if (ajaxResult != null && ajaxResult.isSuccess()) {
                    //开始获取最新频道
                    QueryInfo queryInfo = new QueryInfo();
                    queryInfo.setBoard(sysBoard.getId().toString());
                    int getPrfDataListResult = outputChannelService.getPrfDataList(sysBoard, queryInfo);
//                    System.out.println("设置默认分发频道结果:" + getPrfDataListResult);
                    if (getPrfDataListResult == 0) {
//                        System.out.println("===================重置分发频道成功===========================");
                        return success();
                    }else{
                        return AjaxResult.error("保存设置直播板卡:"+sysBoard.getId()+"默认分发频道失败，请检查网络连接");
                    }
                }
//                System.out.println("直播板卡:" + sysBoard.getId() + " ,设置默认分发频道结束:" + sysBoard.getUrl());
                return ajaxResult;
            }
        }
        return AjaxResult.error("设置直播板卡:"+sysBoard.getId()+"默认分发频道失败，请检查网络连接");
    }


}
